package main

import (
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"path"
	"path/filepath"
	"rabbit/build"
	"runtime"
	"strconv"
	"strings"

	"github.com/erikdubbelboer/gspt"
	"github.com/gin-gonic/gin"
	"github.com/urfave/cli"
)

var FILEDIR = "./data/file/"

var runCmd = cli.Command{
	Name:            "run",
	ShortName:       "",
	Usage:           "Start a rabbit file server",
	SkipFlagParsing: true,
	SkipArgReorder:  true,
	Action: func(*cli.Context) error {
		fmt.Println("rabbit file server ready!")

		router := gin.Default()
		// Set a lower memory limit for multipart forms (default is 32 MiB)
		router.MaxMultipartMemory = 8 << 20 // 8 MiB
		//router.Static("/", "./public")
		router.POST("/upload/:uid/:token", func(c *gin.Context) {
			name := c.PostForm("name")
			email := c.PostForm("email")

			// Source
			file, err := c.FormFile("file")
			if err != nil {
				c.String(http.StatusBadRequest, "get form err: %s", err.Error())
				return
			}

			filename := filepath.Base(file.Filename)
			if err := c.SaveUploadedFile(file, path.Join(FILEDIR, filename)); err != nil {
				c.String(http.StatusBadRequest, "upload file err: %s", err.Error())
				return
			}

			c.String(http.StatusOK, "File %s uploaded successfully with fields name=%s and email=%s.", file.Filename, name, email)
		})
		router.GET("/download/:uid/:token", func(c *gin.Context) {
			if c.Request.RequestURI == "/favicon.ico" {
				return
			}

			fmt.Printf("download url=%s \n", c.Request.RequestURI)

			filename := c.Request.RequestURI[1:]
			enEscapeUrl, err := url.QueryUnescape(filename)
			if err != nil {
				c.Writer.Write([]byte(err.Error()))
				return
			}

			f, err := os.Open("./" + enEscapeUrl)
			if err != nil {
				c.Writer.Write([]byte(err.Error()))
				return
			}

			info, err := f.Stat()
			if err != nil {
				c.Writer.Write([]byte(err.Error()))
				return
			}

			_, contentType := getContentType(filename)
			c.Writer.Header().Set("Content-Disposition", "attachment; filename="+filename)
			c.Writer.Header().Set("Content-Type", contentType)
			c.Writer.Header().Set("Content-Length", strconv.FormatInt(info.Size(), 10))

			f.Seek(0, 0)
			io.Copy(c.Writer, f)

		})
		router.Run(":8080")

		return nil
	},
}

func getContentType(fileName string) (extension, contentType string) {
	arr := strings.Split(fileName, ".")

	// see: https://tool.oschina.net/commons/
	contentType = "application/octet-stream"
	if len(arr) >= 2 {
		extension = arr[len(arr)-1]
		switch extension {
		case "jpeg", "jpe", "jpg":
			contentType = "image/jpeg"
		case "png":
			contentType = "image/png"
		case "gif":
			contentType = "image/gif"
		case "mp4":
			contentType = "video/mpeg4"
		case "mp3":
			contentType = "audio/mp3"
		case "wav":
			contentType = "audio/wav"
		case "pdf":
			contentType = "application/pdf"
		case "doc", "":
			contentType = "application/msword"
		}
	}

	return
}

func main() {
	// hide process arguments from ps output, since they may contain
	// database credentials or other secrets.
	gspt.SetProcTitle("rabbit " + os.Args[0])

	app := cli.NewApp()
	app.Name = build.AppName
	app.Usage = "rabbit im, the lightweight real-time communication tools. file server"
	app.Version = fmt.Sprintf("%s (%s)", build.Version, build.GitCommit)
	app.Author = "tang shun cai"
	app.Commands = []cli.Command{
		runCmd,
	}

	cli.VersionPrinter = func(c *cli.Context) {
		fmt.Printf("%s version %s\n", app.Name, app.Version)
		fmt.Printf("go version %s\n", runtime.Version())
	}
	app.Flags = []cli.Flag{
		cli.StringFlag{
			Name:  "data-dir,d",
			Usage: "(data) Folder to hold state default /var/lib/rabbit/data/" + build.Program + " or ${HOME}/.rabbit/" + build.Program + " if not root",
		},
	}

	if err := app.Run(os.Args); err != nil {
		fmt.Println(err)
	}
}
